package com.melodyframe.common.context.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

import com.melodyframe.common.context.annotation.Model;
import com.melodyframe.common.context.annotation.Variable;
import com.melodyframe.common.context.loader.ContextRequest;

public class ContextUtil {
	@SuppressWarnings("unchecked")
	public static List<ContextRequest<?>> getParameterRequestsFromMethod(
			Method method) {
		List<ContextRequest<?>> requests = new ArrayList<>();
		try {
			ClassPool pool = ClassPool.getDefault();
			pool.insertClassPath(new ClassClassPath(method.getDeclaringClass()));
			CtClass ctClass = pool.get(method.getDeclaringClass().getName());
			ctClass.getDeclaredMethods();
			CtMethod ctMethod = ctClass.getDeclaredMethod(method.getName());

			MethodInfo methodInfo = ctMethod.getMethodInfo();
			Class<?>[] parameterTypes = method.getParameterTypes();
			Annotation[][] parameterAnnotations = method
					.getParameterAnnotations();

			CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
			LocalVariableAttribute attribute = (LocalVariableAttribute) codeAttribute
					.getAttribute(LocalVariableAttribute.tag);

			if (attribute == null) {
				// exception
			}
			int length = parameterTypes.length;
			int pos = Modifier.isStatic(method.getModifiers()) ? 0 : 1;

			for (int i = 0; i < length; i++) {
				ContextRequest<?> request = new ContextRequest<>();
				String variableName = attribute.variableName(i + pos);
				@SuppressWarnings("rawtypes")
				Class classType = parameterTypes[i];
				request.setClassType(classType);
				Annotation[] annotations = parameterAnnotations[i];
				boolean hasAnnotation = false;
				if (null != annotations) {
					for (Annotation annotation : annotations) {
						if (annotation instanceof Variable) {
							Variable variable = (Variable) annotation;
							String name = variable.name();
							if (isNotBlank(name)) {
								request.setName(name);
							} else {
								request.setName(variableName);
							}

							String scope = variable.scope();
							if (isNotBlank(scope)) {
								request.setScope(scope);
							}

							String format = variable.format();
							if (isNotBlank(format)) {
								request.setFormat(format);
							}
							hasAnnotation = true;
							break;
						} else if (annotation instanceof Model) {
							Model model = (Model) annotation;
							String name = model.name();
							if (isNotBlank(name)) {
								request.setName(name);
							}

							String scope = model.scope();
							if (isNotBlank(scope)) {
								request.setScope(scope);
							}
							hasAnnotation = true;
							break;
						}
					}

				}
				if (!hasAnnotation) {
					request.setName(variableName);
				}
				requests.add(request);
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
		return requests;
	}

	private static boolean isNotBlank(String value) {
		return null != value && !"".equals(value);
	}

}
